package com.njtoyo.taxi.admin.logic.business.ride;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.conditions.update.LambdaUpdateChainWrapper;
import com.njtoyo.taxi.admin.library.common.Enum;
import com.njtoyo.taxi.admin.library.payment.ali.AliPayClient;
import com.njtoyo.taxi.admin.library.payment.cmb.CmbPayClient;
import com.njtoyo.taxi.admin.library.payment.common.CmbRefundInfo;
import com.njtoyo.taxi.admin.library.payment.common.PayBasicInfo;
import com.njtoyo.taxi.admin.library.payment.jyb.JybPayClient;
import com.njtoyo.taxi.admin.library.payment.wechat.WxPayClient;
import com.njtoyo.taxi.admin.mapper.master.entity.*;
import com.njtoyo.taxi.admin.mapper.master.enums.*;
import com.njtoyo.taxi.admin.mapper.master.mapper.DriverFlowLogMapper;
import com.njtoyo.taxi.admin.mapper.master.mapper.RechargeMapper;
import com.njtoyo.taxi.admin.mapper.master.mapper.RefundMapper;
import com.njtoyo.taxi.admin.mapper.master.mapper.RideCancellationMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import weixin.popular.bean.paymch.SecapiPayRefundResult;

import java.math.BigDecimal;
import java.util.*;

@Service
@Slf4j
public class CancellationOrderLogic {

    @Autowired
    private RideCancellationMapper rideCancellationMapper;

    @Autowired
    private RefundLogic refundLogic;

    @Autowired
    private RechargeMapper rechargeMapper;

    @Autowired
    private CancellationTransactionLogLogic cancellationTransactionLogLogic;

    @Autowired
    private RefundMapper refundMapper;

    @Autowired
    private AliPayClient aliPayClient;

    @Autowired
    private WxPayClient wxPayClient;

    @Autowired
    private JybPayClient jybPayClient;

    @Autowired
    private DriverFlowLogMapper driverFlowLogMapper;

    // 判断行程订单是否已被退款
    public boolean hasBeenRefunded(CancellationOrder order) {
        return order.getRefunded();
    }

    // 检查行程订单是否已拥有初始化过的退款记录，如果发现拥有已完成的退款记录
    public boolean checkInitializedRefund(Long cancellationOrderId) {
        Refund refund = refundLogic.getByCancellationOrderId(cancellationOrderId);

        return Objects.nonNull(refund) && !RefundState.done.equals(refund.getState());
    }

    public boolean initRefund(CancellationOrder order) {
        Refund refund = new Refund();

        refund.setCustomerId(order.getUserId());
        refund.setNumber(refundLogic.getSnowflakeId());
        refund.setAmount(order.getAmount());
        refund.setFarePaidAmount(order.getFarePaid());
        refund.setState(RefundState.init);
        refund.setRefundableType("CancellationOrder");
        refund.setRefundableId(order.getId());

        if (hasSavingPaid(order)) {
            CancellationTransactionLog log = cancellationTransactionLogLogic.getLogByCancellationOrderId(order.getId());
            Recharge recharge = rechargeMapper.selectById(log.getRechargeId());

            refund.setBalancePayAmount(recharge.getPayAmount());
            refund.setBalanceDonateAmount(recharge.getDonationAmount());
        } else {
            refund.setBalancePayAmount(BigDecimal.ONE);
            refund.setBalanceDonateAmount(BigDecimal.ONE);
        }

        return refundMapper.insert(refund) > 0;
    }

    // 判断有责取消订单是否包含余额支付的记录
    public boolean hasSavingPaid(CancellationOrder order) {
        if (!RideOrderState.done.equals(order.getState())) {
            return false;
        }

        CancellationTransactionLog log = cancellationTransactionLogLogic.getLogByCancellationOrderId(order.getId());

        if (Objects.isNull(log)) {
            return false;
        }

        Recharge recharge = rechargeMapper.selectById(log.getRechargeId());
        if (Objects.isNull(recharge)) {
            return false;
        }

        return Objects.nonNull(log.getBalancePaid()) && log.getBalancePaid().compareTo(BigDecimal.ZERO) > 0;
    }

    // 判断有责取消订单是否包含第三方支付实付的记录
    public boolean hasFarePaid(CancellationOrder order) {
        if (!RideOrderState.done.equals(order.getState())) {
            return false;
        }

        CancellationTransactionLog log = cancellationTransactionLogLogic.getLogByCancellationOrderId(order.getId());
        if (Objects.isNull(log) || Objects.isNull(log.getPayAmount()) || Objects.isNull(log.getPayThrough())) {
            return false;
        }

        List<RideOrderPaidThrough> payThroughList = new ArrayList<>();
        payThroughList.add(RideOrderPaidThrough.wxapp);
        payThroughList.add(RideOrderPaidThrough.wechat);
        payThroughList.add(RideOrderPaidThrough.alipay);
        payThroughList.add(RideOrderPaidThrough.jybwxapp);
        payThroughList.add(RideOrderPaidThrough.unionpay);

        return log.getPayAmount().compareTo(BigDecimal.ZERO) > 0 && payThroughList.contains(log.getPayThrough());
    }

    // 发起支付宝退款
    public boolean initiateAlipayRefund(CancellationOrder order) {
        Refund refund = refundLogic.getByCancellationOrderId(order.getId());

        if (Objects.nonNull(refund)) {
            PayBasicInfo payBasicInfo = new PayBasicInfo();

            payBasicInfo.setOutTradeNo(order.getNumber());
            payBasicInfo.setRefundAmount(order.getFarePaid());
            payBasicInfo.setRufundNo(refund.getNumber());

            // 调用alipay sdk
            return aliPayClient.refund(payBasicInfo);
        }

        return false;
    }

    // 发起微信小程序、APP退款
    public boolean initiateWeChatRefund(CancellationOrder order, Enum.RideRefundWxAppType wxAppType) {
        Refund refund = refundLogic.getByCancellationOrderId(order.getId());

        if (Objects.nonNull(refund)) {
            PayBasicInfo payBasicInfo = new PayBasicInfo();

            payBasicInfo.setWxAppType(wxAppType);

            payBasicInfo.setOutTradeNo(order.getOutTradeNumber());
            payBasicInfo.setNumber(order.getNumber());
            payBasicInfo.setRufundNo(refund.getNumber());

            payBasicInfo.setAmount(order.getFarePaid());
            payBasicInfo.setRefundAmount(order.getFarePaid());


            SecapiPayRefundResult refundResult = wxPayClient.refund(payBasicInfo);
            // 微信支付退款接口返回数据验签;
            if (refundResult.getSign_status() != null && refundResult.getSign_status()) {
                log.info("微信退款接口--接口请求状态(return_code):" + refundResult.getReturn_code());
                log.info("微信退款接口--接口请求状态(return_msg):" + refundResult.getReturn_msg());

                // 退款信息提交成功;
                if ("SUCCESS".equals(refundResult.getReturn_code())) {
                    log.info("微信退款接口--接口请求状态(result_code):" + refundResult.getResult_code());
                    log.info("微信退款接口--接口请求状态(err_code):" + refundResult.getErr_code());
                    log.info("微信退款接口--接口请求状态(err_code_des):" + refundResult.getErr_code_des());

                    return true;
                }
            }

            return false;
        }

        return false;
    }

    // 发起微信小程序退款
    public boolean initiateJrcbWeChatRefund(CancellationOrder order, Enum.RideRefundWxAppType wxAppType) {
        Refund refund = refundLogic.getByCancellationOrderId(order.getId());

        if (Objects.nonNull(refund)) {
            String orderId = IdUtil.getSnowflake(1, 1).nextIdStr();
            CmbRefundInfo refundInfo = new CmbRefundInfo();
            refundInfo.setOrderId(orderId);
            refundInfo.setOrigOrderId(order.getNumber());
            refundInfo.setSubOrderId(orderId);
            refundInfo.setSubOrigOrderId(order.getNumber());
            String amount = Convert.toStr(order.getFarePaid().multiply(new BigDecimal(100)).intValue());
            refundInfo.setTxnAmt(amount);
            refundInfo.setRefundAmt(amount);
            // 调用 sdk
            Map<String, String> result = CmbPayClient.refund(refundInfo);
            if (result == null) {
                log.info("订单RideOrder：{},招商退款接口返回--失败", order);
                return false;
            }
            String errCode = MapUtil.getStr(result, "errCode");
            if (StrUtil.isNotBlank(errCode)) {
                String respMsg = MapUtil.getStr(result, "respMsg");
                log.info("订单RideOrder：{},招商退款接口返回--失败,失败原因：{}", order, respMsg);
                return false;
            }
            String respCode = MapUtil.getStr(result, "respCode");
            if ("SUCCESS".equals(respCode)) {
                log.info("订单RideOrder：{},招商退款接口返回--成功", order);
                return true;
            }
        }

        return false;
    }

    // 获取有责订单实充余额支付金额
    public BigDecimal getPaySavingPaidAmount(Recharge recharge) {
        if (Objects.nonNull(recharge)) {
            return recharge.getPayAmount();
        }

        return BigDecimal.ONE;
    }

    // 获取行程订单赠送余额支付金额
    public BigDecimal getDonationSavingPaidAmount(Recharge recharge) {
        if (Objects.nonNull(recharge)) {
            return recharge.getDonationAmount();
        }

        return BigDecimal.ONE;
    }

    // 根据 cancellationOrderId，将 refund 记录的 state 设置为dong
    public boolean updateRefundStateDoneByCancellationOrderId(Long cancellationOrderId) {
        Refund refund = refundLogic.getByCancellationOrderId(cancellationOrderId);

        if (Objects.isNull(refund)) {
            return false;
        }
        return new LambdaUpdateChainWrapper<>(refundMapper)
                .eq(Refund::getId, refund.getId())
                .set(Refund::getState, RefundState.done)
                .update();
    }

    // 根据rideOrderId，删除对应司机收入流水
    public boolean deleteDriverFlowLogByCancellationOrderId(Long cancellationOrderId) {
        LambdaQueryWrapper<DriverFlowLog> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(DriverFlowLog::getCategory, DriverFlowLogCategory.cancellation_order)
                .eq(DriverFlowLog::getRefId, cancellationOrderId);

        return driverFlowLogMapper.delete(wrapper) > 0;
    }

    // 改无责退款后，修改 rideCancellation
    public boolean updateForRefund(Long rideCancellationId) {
        return new LambdaUpdateChainWrapper<>(rideCancellationMapper)
                .eq(RideCancellation::getId, rideCancellationId)
                .set(RideCancellation::getViolate, RideCancellationViolate.none)
                .set(RideCancellation::getResponsibility, RideCancellationResponsibility.admin)
                .set(RideCancellation::getTriggerBy, RideCancellationTriggerBy.admin)
                .set(RideCancellation::getUpdatedAt, new Date())
                .update();
    }
}
